﻿using Common.Library;
using Common.Model;
using Container.Library;
using DevOps.Logic;
using DevOps.Model;
using Mall.Logic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Network.Library;
using Serialize.Library;
using System;
using System.Text;
using System.Threading.Tasks;

namespace Api.MallManage
{
    /// <summary>
    /// 用户授权特性/请求接口日志记录/参数合法性过滤
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class ClientApiFilter : ActionFilterAttribute
    {
        /// <summary>
        /// 接口请求参数
        /// </summary>
        private StringBuilder action_params = null;

        //设备类型 微信端100 APP端110 PC前端120 PC后端130
        private DeviceType deviceType;

        //是否需要验证
        private bool isValidate = false;

        //是否记录
        private bool isRecord = true;

        /// <summary>
        /// 验证用户信息
        /// </summary>
        /// <param name="deviceType">微信端100 APP端110 PC前端120 PC后端130</param>
        /// <param name="isValidate">是否权限验证</param>
        /// <param name="isRecord">是否记录</param>
        public ClientApiFilter(DeviceType deviceType, bool isValidate, bool isRecord = true)
        {
            this.deviceType = deviceType;
            this.isValidate = isValidate;
            this.isRecord = isRecord;
        }

        /// <summary>
        ///  验证用户信息
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            #region 权限验证
            switch (deviceType)
            {
                case DeviceType.PCBack:
                    if (isValidate)
                    {
                        var id = HttpHelper.GetJwtUserId();
                        var userService = UnityCIContainer.Instance.GetService<ISysUserService>();
                        var userInfo = userService.LoadSingleById(id);

                        ResultJsonInfo<string> resultInfo = new ResultJsonInfo<string>();

                        if (userInfo.Success)
                        {
                            if (!userInfo.Data.is_valid)
                            {
                                resultInfo.Code = ActionCodes.AccountBlocked;
                                resultInfo.Data = "用户被冻结，请联系管理人员！";
                                ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                            }
                        }
                        else
                        {
                            resultInfo.Code = ActionCodes.AccountNotExist;
                            resultInfo.Data = "无用户信息，请重新登录！";
                            ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                        }
                    }
                    break;
                case DeviceType.WeChat:
                    if (isValidate)
                    {
                        var id = HttpHelper.GetJwtUserId();
                        var clientInfoService = UnityCIContainer.Instance.GetService<IClientInfoService>();
                        var userInfo = clientInfoService.LoadSingleById(id);
                        ResultJsonInfo<string> resultInfo = new ResultJsonInfo<string>();
                        if (userInfo.Success)
                        {
                            if (userInfo.Data.is_valid!=(int)IsValid.Valid)
                            {
                                resultInfo.Code = ActionCodes.AccountBlocked;
                                resultInfo.Data = "用户被冻结，请联系管理人员！";
                                ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                            }
                        }
                        else
                        {
                            resultInfo.Code = ActionCodes.AccountNotExist;
                            resultInfo.Data = "无用户信息，请重新登录！";
                            ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                        }
                    }
                    break;
                default:
                    break;
            }
            #endregion

            var requestIp = HttpHelper.GetIP();

            #region 判断是否在黑名单中

            var allNameListInfo = ApiMonitorLogServiceRedis.GetAllNameList();
            if (allNameListInfo.Count > 0)
            {
                var isBlackList = allNameListInfo.Exists(p => p.request_ip.Equals(requestIp) && p.name_type == (int)NameListType.NoAccess);
                if (isBlackList)
                {
                    ResultJsonInfo<string> resultInfo = new ResultJsonInfo<string>();
                    resultInfo.Code = ActionCodes.IllegalOperation;
                    resultInfo.Data = "被禁用IP！";
                    resultInfo.Msg = "被禁用IP！";
                    ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                }
            }

            #endregion

            #region 获取接口获取到的参数

            var descriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;
            if (descriptor.Parameters.Count > 0)
            {
                action_params = new StringBuilder();
                foreach (var item in descriptor.Parameters)
                {
                    if (filterContext.ActionArguments.Count > 0)
                    {
                        action_params.Append($"{{{item.Name}:{ JsonHelper.ToJson(filterContext.ActionArguments[item.Name])}}}");
                    }
                }
            }
            #endregion

            #region 过滤SQL注入

            if (action_params != null)
            {
                bool safeString = StringHelper.IsSafeSqlString(action_params.ToString());
                if (!safeString)
                {
                    ResultJsonInfo<string> resultInfo = new ResultJsonInfo<string>();
                    resultInfo.Code = ActionCodes.IllegalOperation;
                    resultInfo.Data = "包含SQL注入相关的非法字符串！";
                    resultInfo.Msg = "包含SQL注入相关的非法字符串！";
                    ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                }
            }

            #endregion

            #region 防重放攻击
            if (filterContext.HttpContext.Request.Headers.Keys.Contains("timestamp"))
            {
                var timestamp = filterContext.HttpContext.Request.Headers["timestamp"].ToString();

                ApiMonitorLogServiceRedis.GetIpTimestamp(requestIp, timestamp,
                    result =>
                    {
                        ResultJsonInfo<string> resultInfo = new ResultJsonInfo<string>();
                        resultInfo.Code = ActionCodes.IllegalOperation;
                        resultInfo.Data = "重放非法请求！";
                        resultInfo.Msg = "重放非法请求！";
                        ActionException(filterContext, JsonHelper.ToJson(resultInfo));
                    });
                Task.Run(() =>
                {
                    ApiMonitorLogServiceRedis.SetIpTimestamp(requestIp, timestamp);
                });
            }
            else
            {
                ResultJsonInfo<string> resultInfo = new ResultJsonInfo<string>();
                resultInfo.Code = ActionCodes.InvalidOperation;
                resultInfo.Data = "非法请求！";
                resultInfo.Msg = "非法请求！";
                ActionException(filterContext, JsonHelper.ToJson(resultInfo));
            }
            #endregion

            #region 接口请求日记记录操作

            if (isRecord)
            {
                var log = new SafeApiMonitorLogEntity();

                log.request_ip = requestIp;
                //服务名称放到异步中
                log.service_name = ServiceName.MallService.GetEnumItemDescription();

                log.action_name = descriptor.ActionName;
                log.http_method = filterContext.HttpContext.Request.Method;
                if (descriptor.Parameters.Count > 0)
                {
                    log.action_params = action_params.ToString();
                }
                else
                {
                    log.action_params = "";
                }
                log.controller_name = descriptor.ControllerName;
                log.start_time = DateTime.Now;
                log.http_header = JsonHelper.ToJson(filterContext.HttpContext.Request.Headers.Values);
                log.request_path = filterContext.HttpContext.Request.Path.ToString();
                if (log.request_path.IsNotNullOrEmpty())
                {
                    //插入日志
                    Task.Run(() =>
                    {
                        ApiMonitorLogServiceRedis.SaveApiMonitorLog(log);
                        ApiMonitorLogServiceRedis.IncrementApiMonitorNumber(log);
                    });
                }
            }

            #endregion

            base.OnActionExecuting(filterContext);
        }

        /// <summary>
        /// Action执行后发生
        /// </summary>
        /// <param name="actionExecutedContext">执行后的上下文</param>
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
        }

        /// <summary>
        /// 失败返回处理
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="message">失败信息</param>
        public void ActionException(ActionExecutingContext filterContext, string message)
        {
            var _Controller = filterContext.Controller as ControllerBase;
            filterContext.Result = _Controller.Content(message, "application/json;charset=utf-8;");
        }
    }
}
